/*
 * $$LastChangedRevision: 1 $$
 * $$LastChangedBy: msc $$ 
 * 
 */

/*
 * MetadataPanel.java
 *
 */
package org.netbeans.gpx.editor.view.overall;

import org.netbeans.gpx.model.entity.Link;
import org.netbeans.gpx.model.entity.Metadata;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.netbeans.gpx.editor.binding.converter.XMLGregorianCalendarConverter;
import org.netbeans.gpx.editor.GpxDataObject;
import org.netbeans.modules.xml.multiview.ui.SectionView;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;

/**
 *
 * @author msc
 */
public class MetadataPanel extends AbstractMetadataPanel implements
    ListSelectionListener, PropertyChangeListener {

    private XMLGregorianCalendarConverter calendarConverter;

    private ListSelectionModel listSelectionModel;

    private DefaultListModel listModel;

    private LinkEditAction linkEditAction;

    private LinkEditAction linkAddAction;

    private LinkDeleteAction linkDeleteAction;

    /** Creates new form MetadataPanel */
    public MetadataPanel(SectionView sectionView, GpxDataObject gpxDataObject) {
        super(sectionView, gpxDataObject);

        calendarConverter = new XMLGregorianCalendarConverter();

        createListModels();

        createLinkActions();

        initComponents();
        
        setValues();
        addModifiers();

    }

    /**
     * creates models for the list
     */
    private void createListModels() {
        listModel = new DefaultListModel();

        listSelectionModel = new DefaultListSelectionModel();
        listSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listSelectionModel.addListSelectionListener(this);
    }

    /**
     * creates all the necesarry actions
     */
    private void createLinkActions() {

        linkAddAction = new LinkAddAction();
        linkAddAction.addPropertyChangeListener(this);

        linkDeleteAction = new LinkDeleteAction();

        linkEditAction = new LinkListEditAction();
        linkEditAction.addPropertyChangeListener(this);
    }

    private void addModifiers() {
        addModifier(txtName);
        addModifier(txtTime);
        addModifier(txtKeywords);
        addModifier(txtAreaDesc);
        addListDataListener(listModel);
    }

    private void setValues() {
        Metadata metadata = getMetadata();
        if (metadata != null) {
            txtName.setText(metadata.getName());
            txtTime.setText(calendarConverter.convertForward(metadata.getTime()));
            txtKeywords.setText(metadata.getKeywords());
            txtAreaDesc.setText(metadata.getDesc());

            List<Link> links = metadata.getLinks();
            for (Link link : links) {
                listModel.addElement(link);
            }
        }
    }

    @Override
    protected void merge() {

        Metadata metadata = checkMetadata();

        metadata.getLinks().clear();
        for (int i = 0, n = listModel.getSize(); i < n; i++) {
            Link link = (Link) listModel.getElementAt(i);
            metadata.getLinks().add(link);
        }

        super.merge();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        lblName = new javax.swing.JLabel();
        txtName = new javax.swing.JTextField();
        lblDesc = new javax.swing.JLabel();
        scrollDesc = new javax.swing.JScrollPane();
        txtAreaDesc = new javax.swing.JTextArea();
        lblTime = new javax.swing.JLabel();
        txtTime = new javax.swing.JTextField();
        lblKeywords = new javax.swing.JLabel();
        txtKeywords = new javax.swing.JTextField();
        lblLinks = new javax.swing.JLabel();
        scrollLinks = new javax.swing.JScrollPane();
        lstLinks = new javax.swing.JList();
        btnAddLink = new javax.swing.JButton();
        btnRemoveLink = new javax.swing.JButton();
        btnEditLink = new javax.swing.JButton();

        lblName.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.lblName.text")); // NOI18N

        lblDesc.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.lblDesc.text")); // NOI18N

        txtAreaDesc.setColumns(20);
        txtAreaDesc.setRows(5);
        scrollDesc.setViewportView(txtAreaDesc);

        lblTime.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.lblTime.text")); // NOI18N

        lblKeywords.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.lblKeywords.text")); // NOI18N

        lblLinks.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.lblLinks.text")); // NOI18N

        lstLinks.setModel(listModel);
        lstLinks.setCellRenderer(new LinkListCellRenderer());
        lstLinks.setSelectionModel(listSelectionModel);
        scrollLinks.setViewportView(lstLinks);

        btnAddLink.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.btnAddLink.text")); // NOI18N
        btnAddLink.setAction(linkAddAction);

        btnRemoveLink.setText(org.openide.util.NbBundle.getMessage(MetadataPanel.class, "MetadataPanel.btnRemoveLink.text")); // NOI18N

        btnEditLink.setText("...");
        btnEditLink.setAction(linkEditAction);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(lblKeywords)
                            .addComponent(lblTime)
                            .addComponent(lblName, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(txtKeywords, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE)
                            .addComponent(txtName)
                            .addComponent(txtTime)))
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(lblDesc, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(lblLinks))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(scrollDesc)
                            .addComponent(scrollLinks, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(btnAddLink)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(btnRemoveLink)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(btnEditLink)))))
                .addContainerGap(28, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblName)
                    .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblTime)
                    .addComponent(txtTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblKeywords)
                    .addComponent(txtKeywords, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lblDesc)
                    .addComponent(scrollDesc, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lblLinks)
                    .addComponent(scrollLinks, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnAddLink)
                    .addComponent(btnRemoveLink)
                    .addComponent(btnEditLink))
                .addGap(23, 23, 23))
        );

        btnRemoveLink.setAction(linkDeleteAction);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddLink;
    private javax.swing.JButton btnEditLink;
    private javax.swing.JButton btnRemoveLink;
    private javax.swing.JLabel lblDesc;
    private javax.swing.JLabel lblKeywords;
    private javax.swing.JLabel lblLinks;
    private javax.swing.JLabel lblName;
    private javax.swing.JLabel lblTime;
    private javax.swing.JList lstLinks;
    private javax.swing.JScrollPane scrollDesc;
    private javax.swing.JScrollPane scrollLinks;
    private javax.swing.JTextArea txtAreaDesc;
    private javax.swing.JTextField txtKeywords;
    private javax.swing.JTextField txtName;
    private javax.swing.JTextField txtTime;
    // End of variables declaration//GEN-END:variables

    @Override
    public void setValue(JComponent source, Object o) {
        Metadata metadata = checkMetadata();
        if (source == txtName) {
            metadata.setName((String) o);
        }
        else if (source == txtTime) {
            metadata.setTime(calendarConverter.convertReverse((String) o));
        }
        else if (source == txtKeywords) {
            metadata.setKeywords((String) o);
        }
        else if (source == txtAreaDesc) {
            metadata.setDesc((String) o);
        }
    }

    @Override
    public void linkButtonPressed(Object o, String string) {
        //TODO implement
    }

    @Override
    public JComponent getErrorComponent(String string) {
        return null;
    }

    /**
     * The value changed method is invoked when the selection in the list changes.
     * @param event 
     */
    @Override
    public void valueChanged(ListSelectionEvent event) {
        if (!event.getValueIsAdjusting()) {
            if (listSelectionModel.isSelectionEmpty()) {
                //No selection, disable actions
                linkEditAction.setEnabled(false);
                linkDeleteAction.setEnabled(false);
            }
            else {
                int index = getSelectedIndex();

                Link link = new Link(getSelectedLink(index));
                linkEditAction.setLink(link);
                linkEditAction.setEnabled(true);

                linkDeleteAction.setIndex(index);
                linkDeleteAction.setEnabled(true);
            }
        }
    }

    private Link getSelectedLink(int index) {
        return (Link) listModel.getElementAt(index);
    }

    private int getSelectedIndex() {
        return listSelectionModel.getMinSelectionIndex();
    }

    /**
     * The property change method is invoked from the actions.
     * @param event 
     */
    @Override
    public void propertyChange(PropertyChangeEvent event) {

        String propertyName = event.getPropertyName();
        if (LinkEditAction.LINK_PROP.equals(propertyName)) {
            Object source = event.getSource();
            Link link = (Link) event.getNewValue();

            if (source == linkEditAction) {
                int index = getSelectedIndex();
                listModel.remove(index);
                listModel.add(index, link);
            }
            else if (source == linkAddAction) {
                listModel.addElement(link);
            }
        }
    }

    /**
     * cell renderer for the list of links
     */
    private class LinkListCellRenderer extends DefaultListCellRenderer {

        @Override
        public Component getListCellRendererComponent(JList jlist, Object ob,
            int i, boolean bln, boolean bln1) {

            Link link = (Link) ob;
            String text = link.getText();
            String href = link.getHref();
            //take either name or href
            String value = ( text != null && !text.isEmpty() ) ? text : href;
            return super.getListCellRendererComponent(jlist, value, i, bln, bln1);
        }

    }

    /**
     * action to edit a link
     */
    private class LinkListEditAction extends LinkEditAction {

        public LinkListEditAction() {
            super(false);
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            super.actionPerformed(event);
            listSelectionModel.clearSelection();
        }

    }

    /**
     * action to add a new link
     */
    private class LinkAddAction extends LinkEditAction {

        public LinkAddAction() {
            String name = " " + NbBundle.getMessage(getClass(), "CTL.AddLink") + " ";
            putValue(NAME, name);
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            listSelectionModel.clearSelection();
            setLink(new Link());
            super.actionPerformed(event);
        }

    }

    /**
     * action to delete a link
     */
    private class LinkDeleteAction extends AbstractAction {

        /** index of the selected link in the list*/
        private int index;

        private String dlgTitle;

        private String dlgMsg;

        public LinkDeleteAction() {

            dlgTitle = NbBundle.getMessage(getClass(), "DLG.DeleteLink.Title");
            dlgMsg = NbBundle.getMessage(getClass(), "DLG.DeleteLink.Question");

            String name = " " + NbBundle.getMessage(getClass(), "CTL.DeleteLink") + " ";
            putValue(NAME, name);
            setEnabled(false);
        }

        public void setIndex(int index) {
            this.index = index;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            NotifyDescriptor descr = new NotifyDescriptor.Confirmation(dlgMsg, dlgTitle, DialogDescriptor.YES_NO_OPTION);
            if (DialogDisplayer.getDefault().notify(descr) == DialogDescriptor.YES_OPTION) {
                listModel.remove(index);
                listSelectionModel.clearSelection();
            }
        }

    }

}
